<template>
	<a-cascader
		v-if="editorStyle == 'cascader'"
		:class="[
			'app-editor-container',
			'app-dropdown-list',
			`app-dropdown-list-${name}`,
		]"
		:value="curValue"
		:disabled="disabled || readonly"
		:multiple="multiple"
		:options="items"
		:fieldNames="{ children: 'children', label: 'text', value: 'value' }"
		:placeholder="placeholder"
		showCheckedStrategy="SHOW_CHILD"
		@blur="onBlur"
		@focus="onFocus"
		@change="onChange"
	></a-cascader>
	<a-tree-select
		v-else-if="hasChildren"
		:class="[
			'app-editor-container',
			'app-dropdown-list',
			`app-dropdown-list-${name}`,
		]"
		:value="curValue"
		:placeholder="placeholder"
		:allowClear="clearable"
		:tree-data="items"
		:disabled="disabled || readonly"
		:tree-checkable="multiple"
		@blur="onBlur"
		@focus="onFocus"
		@change="onChange"
		:fieldNames="{ children: 'children', label: 'text', value: 'value' }"
	>
	</a-tree-select>
	<a-select
		v-else
		:class="[
			'app-editor-container',
			'app-dropdown-list',
			`app-dropdown-list-${name}`,
		]"
		:value="curValue"
		:options="items"
		:mode="multiple ? 'multiple' : undefined"
		:disabled="disabled || readonly"
		:placeholder="placeholder"
		:allowClear="clearable"
		:showSearch="filterable"
		:filterOption="filterable && filterOption"
		@blur="onBlur"
		@focus="onFocus"
		@change="onChange"
	>
	</a-select>
</template>
<script setup lang="ts">
import { onBeforeMount, Ref, ref } from 'vue';
import { dropdownListProps } from './dropdown-list';
import { IParam, IEvent, ICodeListItem, deepCopy } from '@/core';
import { typeOf } from '@/core';
import { handleEditorNavParams, useEditorTypeParams } from '@/hooks/use-editor';
interface EditorEmit {
	(name: 'component-action', value: IEvent<string>): void;
}
const props = defineProps(dropdownListProps);
const emit = defineEmits<EditorEmit>();
// 类型校验
const {
	validateConfig,
	valueType,
	valueSeparator,
	objectNameField,
	objectIdField,
	objectValueField,
} = useEditorTypeParams();
validateConfig();
const { navContext, navViewParam } = handleEditorNavParams(props);
const hasChildren = ref(false);
let items: Ref<IParam[]> = ref([]);
let codeListData: IParam[] = [];
let curValue: Ref<any> = computed(() => {
	let value: any = props.multiple ? [] : null;
	if (props.value || props.value === 0) {
		if (props.editorStyle == 'cascader') {
			try {
				if (props.value && typeOf(props.value) == 'string') {
					value = JSON.parse(props.value as string);
				}
			} catch {}
		}
		if (props.multiple) {
			if (valueType == 'OBJECTS') {
				value = [];
				(props.value as any[]).forEach((item: any) => {
					if (objectIdField) {
						value.push(item[objectIdField]);
					}
				});
			} else {
				value = (props.value as string).split(
					valueSeparator ? valueSeparator : props.valueSeparator
				);
			}
		} else {
			if (valueType == 'OBJECT') {
				if (objectIdField) {
					value = (props.value as any)[objectIdField];
				}
			} else {
				value = props.value;
				const type = typeOf(value);
				if (type == props.valueType) {
					return value;
				} else {
					if (type === 'number') {
						value = value.toString();
					} else if ((value as String).indexOf('.') == -1) {
						value = parseInt(value as string);
					} else {
						value = parseFloat(value as string);
					}
				}
			}
		}
	}
	return value;
});

const onChange = (selects: any, option: any) => {
	let value: any = null;
	if (props.editorStyle == 'cascader') {
		emit('component-action', {
			name: props.name as string,
			action: 'valueChange',
			data: JSON.stringify(selects),
		});
		return;
	}
	if (props.multiple) {
		if (valueType == 'OBJECTS') {
			const curSelect: IParam[] = [];
			selects.forEach((value: string) => {
				const select = codeListData.find(
					(codeList: IParam) => codeList.value == value
				);
				if (select) {
					curSelect.push(handleObjectParams(select));
				}
			});
			value = curSelect.length > 0 ? curSelect : null;
		} else {
			value = selects.join(
				valueSeparator ? valueSeparator : props.valueSeparator
			);
		}
	} else {
		if (valueType == 'OBJECT') {
			const select = codeListData.find(
				(codeList: IParam) => codeList.value == selects
			);
			if (select) {
				value = handleObjectParams(select);
			}
		} else {
			value = selects;
		}
	}
	emit('component-action', {
		name: props.name as string,
		action: 'valueChange',
		data: value,
	});
	if (props.valueItem) {
		emit('component-action', {
			name: props.valueItem,
			action: 'valueChange',
			data: props.multiple
				? selects.join(valueSeparator ? valueSeparator : props.valueSeparator)
				: selects,
		});
	}
};
/**
 * @description 处理对象类型参数
 * @param select 选中数据
 */
const handleObjectParams = (select: IParam): IParam => {
	const object: IParam = {};
	if (objectNameField) {
		Object.assign(object, {
			[objectNameField]: select['text'],
		});
	}
	if (objectIdField) {
		Object.assign(object, {
			[objectIdField]: select['value'],
		});
	}
	if (objectValueField) {
		Object.assign(object, {
			[objectValueField]: deepCopy(select),
		});
	}
	return object;
};
// 内置筛选
const filterOption = (inputValue: string, option: any) => {
	return option.label.indexOf(inputValue) != -1;
};
const onBlur = () => {
	emit('component-action', {
		name: `${props.name}`,
		action: 'editorBlur',
		data: curValue.value,
	});
};
const onFocus = () => {
	emit('component-action', {
		name: `${props.name}`,
		action: 'editorFocus',
		data: curValue.value,
	});
};

onBeforeMount(() => {
	loadData();
});

const formatCodeList = (items: Array<any>) => {
	let matching = false;
	let result: Array<any> = [];
	try {
		items.forEach((item: any) => {
			const type = typeOf(item.value);
			if (type != props.valueType) {
				matching = true;
				if (type === 'number') {
					item.value = item.value.toString();
				} else {
					if (type == 'null') {
						props.valueType == 'number' ? (item.value = 0) : (item.value = '');
					} else if (item.value.indexOf('.') == -1) {
						item.value = parseInt(item.value);
					} else {
						item.value = parseFloat(item.value);
					}
				}
			}
			result.push(item);
		});
		if (matching) {
			console.warn(
				App.ts(
					'common.generic.codelistcast',
					'代码表值类型和属性类型不匹配，自动强制转换'
				)
			);
		}
		return result;
	} catch (error) {
		console.warn(
			App.ts(
				'common.generic.codelistwarn',
				'代码表值类型和属性类型不匹配，自动强制转换异常，请修正代码表值类型和属性类型匹配'
			)
		);
		return [];
	}
};

const loadData = async () => {
	if (props.codeListTag && props.codeListType) {
		await App.getAppCodeListHelper()
			.getCodeListItems(props.codeListTag, navContext, navViewParam)
			.then((codeListResult: any) => {
				if (codeListResult.ok) {
					const result = formatCodeList(codeListResult.data);
					codeListData = [...result];
					handleLevelCodeList(result);
				}
			})
			.catch((error: any) => {
				console.warn(App.ts('common.generic.codenotexist', '代码表不存在'));
			});
	}
};

// 格式化数据
const handleLevelCodeList = (result: any[]) => {
	const setChildCodeItems = (
		pValue: string,
		result: Array<any>,
		codeItem: any
	) => {
		result.forEach((item: any) => {
			if (item.pvalue == pValue) {
				let valueField: string = item.value;
				setChildCodeItems(valueField, result, item);
				if (!codeItem.children) {
					codeItem.children = [];
				}
				codeItem.children.push(item);
			}
		});
	};
	const handleDefault = () => {
		result.forEach((item: ICodeListItem) => {
			items.value.push({ ...item, label: item.text });
		});
	};
	if (result && result.length > 0) {
		hasChildren.value = result.some((item: any) => {
			return item.pvalue;
		})
			? true
			: false;
		if (hasChildren.value) {
			let list: Array<any> = [];
			result.forEach((item: any) => {
				const index = result.findIndex(
					(_item: any) => item.pvalue == _item.value
				);
				if (index == -1) {
					list.push(deepCopy(item));
				}
			});
			list.forEach((item: any) => {
				setChildCodeItems(item.value, result, item);
			});
			items.value = list;
		} else {
			handleDefault();
		}
	}
};
</script>
